package com.example.myapplication.camera;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;


import java.util.ArrayList;
import java.util.List;

/**
 * Create By TreeRoot
 * Create Time: 2024/01/25 08:43
 * Class Name: CameraHelper
 * Description:
 * 相机工具类，用于打开相机，设置相机参数，预览相机数据
 *
 * @author TreeRoot
 */
public class Camera2Helper {
    private static final String TAG = "CameraHelper";

    //-----------------------------------------------------相机相关----------------------------------------
    /**
     * 相机管理器
     */
    private CameraManager cameraManager;

    /**
     * 在使用的相机对象
     */
    private CameraDevice mCameraDevice;
    /**
     * 相机会话
     */
    private CameraCaptureSession mCaptureSession;

    /**
     * 输出到屏幕的预览
     */
    private Surface mPreviewSurface;
    /**
     * 预览回调的接收者
     */
    private ImageReader mImageReader;
    /**
     * 上下文
     */
    private Context mContext;

    //-----------------------------------------------------显示尺寸----------------------------------------

    /**
     * 预览的视图
     */
    private View previewDisplayView;

    //-----------------------------------------------------显示角度&镜像----------------------------------------

    /**
     * 角度
     */
    private int rotation;
    /**
     * 额外的旋转角度
     */
    private int additionalRotation;
    /**
     * 是否镜像显示
     */
    private boolean isMirror = false;

    /**
     * 方向集合
     */
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 0);
        ORIENTATIONS.append(Surface.ROTATION_90, 90);
        ORIENTATIONS.append(Surface.ROTATION_180, 180);
        ORIENTATIONS.append(Surface.ROTATION_270, 270);
    }

    //-----------------------------------------------------摄像头id----------------------------------------

    /**
     * 在使用的相机ID
     */
    private String mCameraId;

    /**
     * 前置摄像头Id
     */
    private final String frontCameraId = String.valueOf(CameraCharacteristics.LENS_FACING_FRONT);

    //-----------------------------------------------------额外线程----------------------------------------

    /**
     * 后台线程的handler
     */
    private Handler mBackgroundHandler;

    /**
     * 预览回调
     */
    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener;

    /**
     * 预览回调处理的线程
     */
    private HandlerThread mBackgroundThread;


    /**
     * 相机帮助类构造函数
     *
     * @param builder 构造器
     */
    Camera2Helper(Builder builder) {
        this.mContext = builder.getmContext();
        this.mCameraId = builder.getCameraId();
        this.cameraManager = builder.getCameraManager();
        this.previewDisplayView = builder.getPreviewDisplayView();
        this.mOnImageAvailableListener = builder.getCameraListener();
        this.rotation = builder.getRotation();
        this.additionalRotation = builder.getAdditionalRotation();
        if (builder.getPreviewDisplayView() instanceof TextureView) {
            this.isMirror = builder.isMirror;
        } else if (this.isMirror) {
            throw new RuntimeException("mirror is effective only when the preview is on a textureView");
        }
    }


    /**
     * 相机初始化
     */
    public void init() {
        if (getCameraId() == null) {
            return;
        }
        if (previewDisplayView instanceof TextureView) {
            ((TextureView) this.previewDisplayView).setSurfaceTextureListener(textureListener);
        } else if (previewDisplayView instanceof SurfaceView) {
            ((SurfaceView) previewDisplayView).getHolder().addCallback(surfaceCallback);
        }
        if (isMirror) {
            previewDisplayView.setScaleX(-1);
        }
    }

    /**
     * 获取相机ID
     *
     * @return 相机ID  当有两个及以上摄像头时，默认返回前置摄像头ID
     */
    public String getCameraId() {
        try {
            String[] cameraIds = cameraManager.getCameraIdList();
            if (cameraIds.length >= 0) {
                if (cameraIds.length >= 2) {
                    //返回系统前置摄像头
                    return frontCameraId;
                }
                return cameraIds[0];
            }
        } catch (Exception e) {
            Log.i(TAG, "getCameraId: 获取摄像头ID失败");
        }
        return null;

    }

    /**
     * 开始预览
     * 改成从驱动里去获取摄像头id了
     */
    @SuppressLint("MissingPermission")
    public void start() {
        if (mCameraId == null) {
            Log.i(TAG, "gmCameraId  is null");
            return;
        }
        try {
            cameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (Exception e) {
            Toast.makeText(mContext, "错误的相机id，未能成功连接相机!", Toast.LENGTH_SHORT).show();
            Log.i(TAG, "getCameraId: 获取摄像头ID失败");
        }
    }

    /**
     * 打开摄像头的回调
     * 这里不要直接把  ImageReader.newInstance改成NV21。因为压根不生效
     * 这里不要直接把  ImageReader.newInstance改成NV21。因为压根不生效
     * 这里不要直接把  ImageReader.newInstance改成NV21。因为压根不生效
     * 这里不要直接把  ImageReader.newInstance改成NV21。因为压根不生效
     */
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            Log.i(TAG, "onOpened: 打开了一个摄像头");
            mCameraDevice = camera;
            mImageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2);
            startBackgroundThread();
            if (mBackgroundHandler != null) {
                openCream();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            Log.d(TAG, "onDisconnected");
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            Log.e(TAG, "Camera Open failed, error: " + error);
            release();
        }
    };

    /**
     * 打开摄像头
     */
    public void openCream() {
        try {
            CaptureRequest.Builder captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 添加输出到屏幕的surface
            List<Surface> surfaces = new ArrayList<>();
            if (mPreviewSurface != null) {
                captureRequestBuilder.addTarget(mPreviewSurface);
                surfaces.add(mPreviewSurface);
            }
            // 添加输出到ImageReader的surface，从ImageReader中获取预览数据了
            captureRequestBuilder.addTarget(mImageReader.getSurface());
            surfaces.add(mImageReader.getSurface());
            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getCameraOri(this.rotation));
            captureRequestBuilder.build();
            // 创建一个CameraCaptureSession来进行相机预览。
            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mCaptureSession = session;
                    // 设置连续自动对焦和自动曝光
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                    CaptureRequest captureRequest = captureRequestBuilder.build();
                    try {
                        // 一直发送预览请求
                        mCaptureSession.setRepeatingRequest(captureRequest, null, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        Log.i(TAG, "sendImg: " + e.getMessage());
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.e(TAG, "ConfigureFailed. session: mCaptureSession");
                }
            }, mBackgroundHandler);
            //创建图像处理的回调函数
            mImageReader.setOnImageAvailableListener(this.mOnImageAvailableListener, null);
        } catch (CameraAccessException e) {
            Log.i(TAG, "openCream: " + e.getMessage());
        }
    }

    /**
     * 获取相机方向
     *
     * @param rotation 设备旋转角度
     * @return 相机方向
     */
    public int getCameraOri(int rotation) throws CameraAccessException {
        int degrees = rotation * 90;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
            default:
                break;
        }

        additionalRotation /= 90;
        additionalRotation *= 90;
        degrees += additionalRotation;

        return getOriResult(degrees);
    }

    /**
     * 获取角度值
     *
     * @param degrees 角度
     * @return 反正
     * @throws CameraAccessException 异常
     */
    private int getOriResult(int degrees) throws CameraAccessException {
        int result = 0;
        CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(mCameraId);
        Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
        Integer sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
            if (sensorOrientation != null) {
                result = (sensorOrientation + degrees) % 360;
                result = (360 - result) % 360;
            }
        } else {
            if (sensorOrientation != null) {
                result = (sensorOrientation - degrees + 360) % 360;
            }
        }
        return result;
    }


    /**
     * 摄像头是否关闭
     *
     * @return true / false
     */
    @SuppressLint("all")
    public boolean isStopped() {
        synchronized (this) {
            return cameraManager == null;
        }
    }

    /**
     * 释放摄像头以及带来的属性
     */
    public void release() {
        synchronized (this) {
            stopBackgroundThread();
            if (this.mCameraDevice != null) {
                this.mCameraDevice.close();
                this.cameraManager = null;
            }
            this.previewDisplayView = null;
            this.mBackgroundThread = null;
            this.mBackgroundHandler = null;
        }
    }


    /**
     * 用于监听 TextureView 的 SurfaceTexture 创建、大小改变、销毁等事件。通过实现该接口，并将其设置给 TextureView
     */
    private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        /**
         * 获取到 SurfaceTexture 对象，并进行相应的初始化工作，比如打开相机、开始预览等。
         */
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
            mPreviewSurface = new Surface(surfaceTexture);
        }

        /**
         * 以获取到 TextureView 的新尺寸，并相应地调整或重置相关的视图或绘制参数
         */
        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
            Log.i(TAG, "onSurfaceTextureSizeChanged: " + width + "  " + height);
        }

        /**
         * 资源释放的操作，比如停止相机预览、释放相机等
         * @param surfaceTexture The surface about to be destroyed
         */
        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
            release();
            return false;
        }

        /**
         * 获取到 TextureView 的更新通知，可以用于实时监测 TextureView 的内容变化
         */
        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {

        }
    };

    /**
     * 用于监听 SurfaceHolder 的创建、大小改变、销毁等事件。通过实现该接口，并将其设置给 SurfaceHolder，可以在合适的时机处理这些事件。
     */
    private final SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
        /**
         *  当 SurfaceHolder 创建时的处理逻辑，比如初始化相机、打开预览等
         */
        @Override
        public void surfaceCreated(@NonNull SurfaceHolder holder) {
        }

        /**
         *  当 SurfaceHolder 大小或格式发生变化时的处理逻辑，比如获取宽高、调整参数等
         */
        @Override
        public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

        }

        /**
         * 当 SurfaceHolder 销毁时的处理逻辑，比如停止相机预览、释放相机等资源
         */
        @Override
        public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
            release();
        }
    };


    /**
     * 切换摄像头
     *
     * @return todo
     */
    @SuppressLint("all")
    public boolean switchCamera() {
        //todo 切换摄像头
        release();
        start();
        return true;
    }

    /**
     * 启动后台线程
     */
    private void startBackgroundThread() {
        if (mBackgroundThread == null || mBackgroundHandler == null) {
            Log.v(TAG, "startBackgroundThread");
            mBackgroundThread = new HandlerThread("CameraBackground");
            mBackgroundThread.start();
            mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
        }
    }

    /**
     * 停止后台线程
     */
    private void stopBackgroundThread() {
        Log.v(TAG, "stopBackgroundThread");
        if (mBackgroundThread != null) {
            mBackgroundThread.quitSafely();
            try {
                mBackgroundThread.join();
                mBackgroundThread = null;
                mBackgroundHandler = null;
            } catch (InterruptedException e) {
                Log.e(TAG, "停止后台线程发生错误" + e.getMessage());
            }
        }

    }
}

